﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace Acoris.Foundation
{
    public sealed class Deque<T>
    {

        T[] _array;
        int _capacity;
        int _length;
        int _tail;
        int _head;

        #region Constructor

        public Deque() : this(4) { }

        public Deque(int capacity)
        {
            _capacity = capacity;
            _array = new T[_capacity];
            _length = 0;
            _tail = 0;
            _head = 0;
        }

        #endregion

        #region Head

        public T PopHead()
        {
            // 队列尾部弹出
            if(_length == 0 || _head == _capacity) {
                throw new InvalidOperationException(ExceptionThrowHelper.DequePopException);
            }
            var val = _array[_head + 1 ];
            _array[_head + 1] = default(T);
            _head++;
            _length--;
            return val;
        }

        public void PushHead(T item)
        {
            // 队首为自减操作
            if (_capacity == _length || _head == _tail) {
                Capacity = _capacity * 2;
            }

            if(_head == 0) {
                _head = _capacity - 1;
            }
            _array[_head--] = item;
            _length++;
        }

        #endregion

        #region Tail

        public T PopTail()
        {
            if(_length == 0 || _tail == 0) {
                throw new InvalidOperationException(ExceptionThrowHelper.DequePopException);
            }
            var val = _array[_tail - 1];
            _array[_tail - 1] = default(T);
            _tail--;
            _length--;
            return val;
        }

        public void PushTail(T item)
        {
            //队尾为自增操作
            if(_capacity == _length || _tail == _head) {
                Capacity = _capacity * 2;
            }

            _array[_tail++] = item;
            _length++;
        }

        #endregion

        #region Internal Method

        internal int GetTail() => _tail;
        internal int GetHead() => _head;
        internal T[] GetArray() => _array;

        #endregion

        private void ResizeCapacity(int newCapacity)
        {
            var old = _array;
            var newTail = ComputeNewTailPosition(newCapacity);
            var newHead = ComputeNewHeadPosition(newCapacity);
            _array = new T[newCapacity];

        }

        private int ComputeNewTailPosition(int newCapacity)
        {
            return _tail;
        }

        private int ComputeNewHeadPosition(int newCapacity)
        {
            var offset =  newCapacity - _capacity;
            return _head + offset;
        }

        #region Property

        public int Capacity {
            get {
                return _capacity;
            }
            set {
                if(value < _capacity) {
                    throw new InvalidOperationException(ExceptionThrowHelper.CollectionResizeCapacityException);
                }
                ResizeCapacity(value);
                _capacity = value;
            }
        }

        public int Count {
            get {
                return _length;
            }
        }

        #endregion
    }
}
